//
// ProcessManager.cpp
// Usage: Manage process in system, only manage, not care about parent-child 
//        relation ship
// CreateDate: 2009-04-16
// Author: MaJiuyue CaiRuicheng
//
#include "ProcessManager.h"
#include "Scheduler.h"

extern void proc0();

CProcessManager::CProcessManager()
	: m_NextPid(0), m_PidBitmap(MAX_PROCESS_NR)
{
	/* Init core.ProcessManager resource */
	Resource * res = new Resource(this);
	ResourceManager.CreateResource(res, ServiceCallInterface::ProcessManager::ResourceName);
	res->RegisterInterface(
		(Resource::CallInterface1)&CProcessManager::GetProcessByPid,
		ServiceCallInterface::ProcessManager::SCIID_GetProcessByPid
	);
	res->RegisterInterface(
		(Resource::CallInterface1)&CProcessManager::CreateProcess,
		ServiceCallInterface::ProcessManager::SCIID_CreateProcess
	);
	res->RegisterInterface(
		(Resource::CallInterface1)&CProcessManager::DestroyProcess,
		ServiceCallInterface::ProcessManager::SCIID_DestroyProcess
	);
	res->RegisterInterface(
		(Resource::CallInterface1)&CProcessManager::CreateProcessKNL,
		ServiceCallInterface::ProcessManager::SCIID_CreateProcessKNL
	);
}


CProcessManager::~CProcessManager()
{
	panic("core.ProcessManager destructed.");
}

Process * CProcessManager::CreateProcess(pid_t parent)
{
	// Get a new pid for child process
	pid_t pid = GetPid();

	// Let parent process fork it's child process
	Process * proc = GetProcessByPid(parent)->CreateChildProcess(pid);
	
	//
	proc->GetThread()->SetRegisterValue(REGS_EAX, 0);

	// Add to process map
	m_ProcessMap.add(pid, proc);

	// Set child process return value
	proc->GetThread()->SetRegisterValue(REGS_EAX, 0);

	// Add to schedule queue
	AddSchedule(proc);

	return proc;
}

//!!!! IMPORTENT !!!!
//NEVER CALLED THIS FOR USER PROCESS, FOR KERNEL ONLY
Process * CProcessManager::CreateProcessKNL(int priority)
{
	// Get a new pid for this process
	pid_t pid = GetPid();

	// Create new process
	Process * proc = new Process(pid, priority);

	// Add to process map
	m_ProcessMap.add(pid, proc);

	// If pid==0 means it is the first process created, whick will restart
	// immediately do not need to be put into schedule queue.
	if(pid!=0)
	{
		// Add to schedule queue
		AddSchedule(proc);
	}

	// Create Okay, return
	return proc;
}

void CProcessManager::DestroyProcess(pid_t pid)
{
	Process * proc = m_ProcessMap.lookup(pid);

	if(proc!=NULL)
		panic("Try to destory process none exist process pid %d.", pid);

	// Remove form process map
	m_ProcessMap.remove(proc->GetPID());

	
	// Release process resource
	delete proc;
}

Process * CProcessManager::GetProcessByPid(pid_t pid)
{
	return m_ProcessMap.lookup(pid);
}

pid_t CProcessManager::GetPid()
{
	pid_t pid = m_NextPid;

	// Find a usable pid
	while(m_PidBitmap.test(pid))
		pid = (pid + 1) % MAX_PROCESS_NR;

	// Set it as used
	m_PidBitmap.set(pid);

	// Set next pid
	m_NextPid = (m_NextPid + 1) % MAX_PROCESS_NR;

	return pid;
}

void CProcessManager::PutPid(pid_t pid)
{
	m_PidBitmap.clear(pid);
}

void CProcessManager::AddSchedule(Process * proc)
{
	Resource * res = ResourceManager.RequestResource(
		ServiceCallInterface::Scheduler::ResourceName
	);
	res->CallSCI(
		ServiceCallInterface::Scheduler::SCIID_AddScheduleObject,
		(u32)proc
	);
}

